#ifndef RENDERER_H
#define RENDERER_H

#include <QImage>
#include <gtypes/Vector3.h>
#include <gtypes/Vector2.h>
#include <gtypes/Matrix4.h>

#include "Light.h"

struct RendererVertex
{
	gtypes::Vector3 pos;
	gtypes::Vector2 tex;
	float r,g,b;

};

class Vertex3D
{
public:
	gtypes::Vector3 pos,normal;
	gtypes::Vector2 tex;
	float r,g,b;
};
class Interpolant
{
public:
    float x,z,r,g,b,u,v,invz,invu,invv;
    Interpolant(float _x,float _z,float _invz,float _r,float _g,float _b,float _u,float _v,float _invu,float _invv);
    void set(float _x,float _z,float _invz,float _r,float _g,float _b,float _u,float _v,float _invu,float _invv);
    void operator +=(Interpolant& i);
    void operator -=(Interpolant& i);
    void operator /=(float f);

};


class Renderer
{
public:

	Renderer();
	
        /**
        * Model view aspect ratio.
        * @return m_width)/m_height Calculate aspect ratio.
        */
        float aspect() { return ((float) m_width)/m_height; }

        /**
        * Draws the polygon.
        */
        virtual void render(RendererVertex v[3] );

        /**
        * Auxiliary drawing function.
        */
        virtual void scan(unsigned char* p,int len,Interpolant base,Interpolant& diff)=0;

        /**
        * Draws a segment of the triangle.
        * @param ystart Drawing start position.
        * @param yend Drawing end position.
        * @param yinc Drawing increment.
        * @param base Interpolation base.
        * @param left Left interpolation point.
        * @param right Right interpolation point.
        */
        void drawTriangleSegment(float ystart,float yend,float yinc,Interpolant base, Interpolant left, Interpolant right);

        /**
        * Renders the triangle defined by 3 vertices.
        * @param v1 First vertex.
        * @param v2 Second vertex.
        * @param v3 Third vertex.
        */
        void render(RendererVertex v1, RendererVertex v2, RendererVertex v3 ); // convenience function

        /**
        * Sets the target on which the texture will be drawn.
        * @param target Texture target.
        */
        virtual void setTarget(QImage* target);

        /**
        * Rotates model view around the specified axis by the specified angle.
        * @param x X-axis for rotation.
        * @param y Y-axis for rotation.
        * @param z Z-axis for rotation.
        * @param angle The angle of rotation.
        */
        void rotate(float x, float y, float z, float angle);

        /**
        * Translates the model view by xyz coordinates.
        * @param x X-axis translation.
        * @param y Y-axis translation.
        * @param z Z-axis translation.
        */
        void translate(float x, float y, float z);

        /**
        * Scales the model view by selected factor.
        * @param factor Scaling factor.
        */
        void scale(float factor);

        /**
        * Sets model view matrix identity.
        */
        void identity();

        /**
        * Sets the projection matrix for converting 3D coordinates to 2D.
        * @param fov Camera angle.
        * @param aspect Screen aspect ratio.
        * @param near Plain closest to the camera.
        * @param far Plain furthest from the camera.
        */
        void setProjectionMatrix( float fov, float aspect, float near, float far );

        /**
        * Sets camera perspective.
        * @param eye Eye position.
        * @param target Object position.
        * @param up Head direction vector.
        */
	void lookAt(const gtypes::Vector3 &eye, const gtypes::Vector3 &target, const gtypes::Vector3 &up);

        /**
        * Sets camera perspective.
        * @param eye Eye position.
        * @param target Object position.
        * @param up Head direction vector.
        */
        void lookAt(const float *eye, const float *target, const float *up);

        /**
        * Sets a texture to the model.
        * @param texture Texture to be added.
        */
        void setTexture( QImage *texture );

        /**
        * Converts 3D vertex coordinates to 2D.
        * @param vertex Vector of Vertex3D vertices to be transformed.
        * @param out Array of the resulting transformed 2D vertices.
        */
        void transform(std::vector<Vertex3D>& vertex, RendererVertex* out);

        /**
        * Sets ambient light to selected RGB color.
        * @param r Red color component of the light.
        * @param g Green color component of the light.
        * @param b Blue color component of the light.
        */
        void setAmbientLight(float r, float g, float b);

        /**
        * Add lights to the model.
        * @param light List of lights to be added.
        */
        void addLight(Light* light);

        /**
        * Removes the lights selected.
        * @param light List of lights to remove.
        */
        void removeLight(Light* light);

        /**
        * Removes all lights.
        */
        void clearLights();

        const gtypes::Matrix4& getModelviewMatrix() { return m_modelviewMatrix; }


protected:
	int m_nLights;
        gtypes::Matrix4 m_modelviewMatrix,m_projectionMatrix,m_combinedMatrix;
        QImage* m_target;
        unsigned char* m_data, *m_tex;
        int m_width,m_height,m_stride,m_texw,m_texh;
        float m_ambientR, m_ambientG, m_ambientB;
        QList<Light*> m_lights;

        void m_arrangeVerticesCCW(RendererVertex& v1, RendererVertex& v2, RendererVertex& v3);
        void m_arrangeVerticesY(RendererVertex& v1, RendererVertex& v2, RendererVertex& v3);

	QImage *m_texture;
};

#endif // RENDERER_H
